﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using SCG = System.Collections.Generic;
using System.Linq;
using Nemerle.Assertions;
using Nemerle.Extensions;
using NRails.Database.Schema;
using BLToolkit.Data;
using Nemerle.Logging;

namespace NRails.Migrations
{
  public class Migration : ActionHolder[MigrationAction], IMigration
  {
      mutable schema : DBSchema;
      protected mutable db : DbManager;
      version : string;
      protected mutable needScope : bool;
      
      protected this([NotNull]version : string)
      {
          this.version = version;
          this.needScope = true;
      }

      #region Helpers
      private GetTable([NotNull]name : string) : TableSchema
      {
          AssertSchema();
          
          def table = schema.GetTable(name);
         
          when (table == null) throw ArgumentException($"Table '$name' not found", "name");
          
          table;
      }
      
      private RunActions([NotNull]table : TableSchema, [NotNull]action : TableActions -> void) 
         : (TableSchema * list[TableAction])
      {
          def actions = TableActions(schema, table);

          action(actions);
          
          (table, (actions : IActionHolder[TableAction]).GetActions())
      }
      
      private AssertSchema() : void
      {
          when (schema == null) throw InvalidOperationException("Schema not set");
      }
      #endregion
      
      #region IMigration
      _AssignSchema([NotNull] schema : DBSchema, [NotNull]db : DbManager) : void implements IMigration.AssignSchema
      {
          this.schema = schema;
          this.db = db;
      }
      
      _Up() : void implements IMigration.Up
      {
          Up();
      }

      _Down() : void implements IMigration.Down
      {
          Down();
      }
      
      Version : string implements IMigration.Version
      {
          get {version;}
      }

      NeedScope : bool implements IMigration.NeedScope
      {
          get { needScope }
      }
      #endregion
      
      protected CreateTable([NotNull] name : string, [NotNull] action : TableActions -> void) : void
      {
          def table = TableSchema();
          table.Name = name;
          table.Columns = array[];
          table.Keys = array[];
          table.Indexes = array[];
          schema.Tables.Add(table);
          AddAction(MigrationAction.CreateTable(RunActions(table, action)));
      }

      protected ChangeTable([NotNull] name : string, [NotNull] action : TableActions -> void) : void
      {
          AddAction(MigrationAction.ChangeTable(RunActions(GetTable(name), action)));
      }

      protected RenameTable([NotNull] name : string, [NotNull] newName : string) : void
      {
          AddAction(MigrationAction.RenameTable(GetTable(name), newName));
      }
      
      protected DropTable([NotNull] name : string) : void
      {
          AddAction(MigrationAction.DropTable(GetTable(name)));
      }
      
      protected virtual Up() : void
      {
      }

      protected virtual Down() : void
      {
      }
   }
}
